/**
 * PDF查看器页面 - 支持签名功能
 * 
 * 核心原则：
 * 1. 标准A4尺寸：所有图片都是标准A4大小的PDF/DOC文档截图
 * 2. 1:1比例：画板和图片比例完全1:1，无任何误差
 * 3. 精确还原：签名坐标能够精确还原到原始位置
 * 
 * 坐标转换公式：
 * - 缩放因子 = A4宽度(595pt) / 屏幕显示宽度
 * - Canvas坐标 = 屏幕坐标 / 当前缩放比例
 * - PDF坐标 = Canvas坐标 × 缩放因子
 * - 加载时：Canvas坐标 = PDF坐标 / 缩放因子
 */

// 页面间距常量（像素）
const PAGE_SPACING = 20; // 页面间距，应与 WXSS 中 .pdf-page 的 margin-bottom 一致

// 标准A4尺寸常量
const A4_WIDTH_PT = 595;  // A4宽度（PDF点数）
const A4_HEIGHT_PT = 842; // A4高度（PDF点数）

// 引入依赖
const api = require('../../utils/api');
const toast = require('../../utils/toast');
const request = require('../../utils/request');
const { IMG_URL } = require('../../utils/request'); // 引入IMG_URL

// 默认头像URL
const defaultAvatarUrl = '/assets/images/wxlogo.png';

Page({
  data: {
    imageUrls: [],
    pageHeights: [],
    allPaths: {}, // 存储所有页面的持久化笔迹
    initialPaths: {}, // 存储初始加载的笔迹，用于区分新添加的

    // 视图尺寸
    canvasWidth: 0, // 屏幕总宽度
    availableWidth: 0, // 减去边距后的可用宽度
    contentWidth: 0,
    contentHeight: 0,
    
    // 设备信息
    devicePixelRatio: 1, // 设备像素比
    screenWidth: 0, // 设备屏幕宽度
    windowWidth: 0, // 可视窗口宽度
    marginPx: 0, // 边距像素值
    
    // PDF实际尺寸数据
    originalWidths: [], // 存储每个PDF页面的原始宽度
    originalHeights: [], // 存储每个PDF页面的原始高度
    scaleFactors: [], // 存储每个页面的缩放因子 (A4尺寸到屏幕尺寸的转换比例)
    
    // A4尺寸信息
    a4Width: A4_WIDTH_PT, // A4宽度（PDF点数）
    a4Height: A4_HEIGHT_PT, // A4高度（PDF点数）

    // 模式控制
    isSigning: false,
    isDrawing: false,
    
    // 签名相关
    penColor: 'black', // 默认黑色，更像钢笔
    penWidth: 3, // 最大宽度
    minPenWidth: 1.5, // 最小宽度
    currentDrawingPath: [], // 临时存储当前正在绘制的笔迹
    showColorPanel: false, // 控制颜色选择面板的显示
    
    // 签署信息相关
    showSignatureInfo: false, // 控制签署信息弹框的显示
    signatureList: [], // 存储签署信息列表

    // UI 相关
    currentPage: 1,
    pageTops: [], // 存储每页的顶部位置
    signingPaths: [], // 临时存储当前签名会话的所有笔迹
    lastPoint: null, // 用于实时计算笔锋
    pageIndicatorFlash: false, // 控制页码指示器闪动
    
    // 图片加载状态
    imagesLoading: true, // 控制loading效果的显示
    loadedImagesCount: 0, // 已加载的图片数量
    
    // 登录相关
    showLoginModal: false, // 控制登录弹窗显示
    tempUserInfo: {
      avatarUrl: '',
      nickName: '',
      uid: ''
    }, // 临时存储用户信息
    defaultAvatarUrl: defaultAvatarUrl, // 添加默认头像URL到data中
    IMG_URL: IMG_URL, // 添加IMG_URL到data中
    signModel: 1, // 新增signModel到data中
    fileId: '', // 文件ID，用于导出
    scaleValue: 1, // 当前缩放值
    documentTitle: '', // 文档标题，用于分享
  },

  // 运行时变量
  viewState: { x: 0, y: 0, scale: 1 }, // 存储视图的实时状态
  systemInfo: null,
  movableAreaTop: 0, // movable-area 距离顶部的距离
  movableAreaLeft: 0, // movable-area 距离左侧的距离
  pageCanvases: {}, // 页面 Canvas 上下文
  signingCanvas: null, // 签名 Canvas 对象
  signingContext: null, // 签名 Canvas 上下文

  onLoad(options) {
    // 保存pdfId到实例变量
    this.options = options || {};
    
    // 启用分享菜单
    wx.showShareMenu({
      withShareTicket: true,
      menus: ['shareAppMessage']
    });
    
    // 初始化防抖函数
    this.debouncedUpdateScale = this.debounce((scale) => {
      this.setData({ scaleValue: scale });
    }, 100);
    
    // 初始化边界提示状态
    this.boundaryToastShown = false;
    
    wx.getSystemInfo({
      success: (res) => {
        this.systemInfo = res;
        const canvasWidth = res.windowWidth;
        
        // 计算实际可用宽度 (考虑左右边距)
        const marginRpx = 60; // 左右边距的总和 (30rpx * 2)
        const marginPx = marginRpx * res.windowWidth / 750; // rpx 转 px
        const availableWidth = canvasWidth - marginPx; 
        
        // 计算设备像素比
        const dpr = res.pixelRatio || 1;
        
        // 计算A4尺寸到屏幕尺寸的缩放因子
        // 这是确保1:1比例的关键 - 所有坐标转换都基于此
        const a4ScaleFactor = A4_WIDTH_PT / availableWidth;
        
        // 保存各种宽度值和设备信息，便于后续使用
        this.setData({
          canvasWidth: canvasWidth,  // 屏幕总宽度
          availableWidth: availableWidth,  // 减去边距后的可用宽度
          contentWidth: canvasWidth,
          devicePixelRatio: dpr,  // 设备像素比
          screenWidth: res.screenWidth,  // 设备屏幕宽度
          windowWidth: res.windowWidth,  // 可视窗口宽度
          marginPx: marginPx,  // 边距像素值
          scaleValue: 1, // 初始化缩放值
          initialPaths: {} // 初始化初始路径对象
        });
        
        // 保存页面左边距，用于计算精确的页面左上角坐标
        this.pageLeftMargin = marginPx / 2; // 左边距是总边距的一半
        
        console.log(`[坐标系统] 设备信息 - 屏幕宽度: ${res.screenWidth}px, 窗口宽度: ${res.windowWidth}px, 像素比: ${dpr}`);
        console.log(`[坐标系统] 布局信息 - 总宽度: ${canvasWidth}px, 边距: ${marginPx}px, 可用宽度: ${availableWidth}px, 左边距: ${this.pageLeftMargin}px`);
        console.log(`[坐标系统] A4缩放因子: ${a4ScaleFactor} (A4宽度${A4_WIDTH_PT}pt / 可用宽度${availableWidth}px)`);
        console.log(`[坐标系统] 坐标转换流程: 屏幕坐标 -> 视图相对坐标 -> 内容相对坐标 -> A4坐标`);
        
        // 如果有文档ID，尝试通过API加载文档数据
        if (options && options.pdfId) {
          this.loadDocumentData(options.pdfId);
          

        } else if (options && options.imageUrls) {
          // 兼容旧版分享的方式，直接传入图片URLs
          this.loadImages(options);
        } else {
          // 没有传入pdfId也没有传入imageUrls，显示测试图片
          this.loadImages({});
        }
      }
    });
  },

  loadImages(options) {
    let imageUrls = [];
    let originalWidths = [];
    let originalHeights = [];
    
    if (options && options.imageUrls) {
      try {
        imageUrls = JSON.parse(decodeURIComponent(options.imageUrls));
        
        // 尝试解析PDF原始尺寸
        if (options.originalWidths && options.originalHeights) {
          originalWidths = JSON.parse(decodeURIComponent(options.originalWidths));
          originalHeights = JSON.parse(decodeURIComponent(options.originalHeights));
        }
      } catch (e) {
        console.error("解析图片URL或尺寸失败", e);
      }
    }

    if (!imageUrls || imageUrls.length === 0) {
      // 使用实际存在的测试图片
      imageUrls = [
        'https://xueshanbanlv-1364336512.cos.ap-beijing.myqcloud.com/web/024bed3c-e8f4-476e-a54e-f09929b43e0f.png'
      ];
      // 测试图片使用标准A4尺寸
      originalWidths = [A4_WIDTH_PT];  // A4宽度
      originalHeights = [A4_HEIGHT_PT]; // A4高度
      wx.showToast({ title: '使用测试图片', icon: 'none' });
    }

    const pageHeights = new Array(imageUrls.length).fill(0);
    const scaleFactors = new Array(imageUrls.length).fill(0); // 初始为0，后续计算
    const allPaths = {};
    const initialPaths = {};
    
    // 确保所有页面都使用标准A4尺寸
    if (originalWidths.length === 0 || originalHeights.length === 0) {
      originalWidths = new Array(imageUrls.length).fill(A4_WIDTH_PT);
      originalHeights = new Array(imageUrls.length).fill(A4_HEIGHT_PT);
    }
    
    // 确保所有页面都有对应的尺寸
    while (originalWidths.length < imageUrls.length) {
      originalWidths.push(A4_WIDTH_PT);
    }
    while (originalHeights.length < imageUrls.length) {
      originalHeights.push(A4_HEIGHT_PT);
    }
    
    imageUrls.forEach((_, index) => {
      allPaths[index] = [];
      initialPaths[index] = [];
    });

    this.pageTops = [0]; // 第一页顶部位置为0
    for (let i = 1; i < imageUrls.length; i++) {
      // 前一页的顶部位置 + 前一页的高度 + 页面间距
      this.pageTops[i] = this.pageTops[i-1] + pageHeights[i-1] + PAGE_SPACING;
    }

    this.setData({
      imageUrls,
      pageHeights,
      allPaths,
      initialPaths,
      originalWidths,
      originalHeights,
      scaleFactors,
      imagesLoading: true,
      loadedImagesCount: 0
    });
  },

  onImageLoad(e) {
    const index = e.currentTarget.dataset.index;
    const { width, height } = e.detail;
    
    // 获取原始PDF尺寸
    const originalWidth = this.data.originalWidths[index] || A4_WIDTH_PT;
    const originalHeight = this.data.originalHeights[index] || A4_HEIGHT_PT;
    
    // 计算页面高度 - 保持图片原始宽高比
    const pageHeight = height * (this.data.availableWidth / width);
    
    // 计算A4尺寸到屏幕尺寸的缩放因子
    // 这是确保1:1比例的关键 - 所有坐标转换都基于此
    const scaleFactor = originalWidth / this.data.availableWidth;
    
    // 更新页面高度和缩放因子
    const newPageHeights = [...this.data.pageHeights];
    newPageHeights[index] = pageHeight;
    
    const newScaleFactors = [...this.data.scaleFactors];
    newScaleFactors[index] = scaleFactor;
    
    // 更新页面顶部位置
    this.pageTops = [0]; // 第一页顶部位置为0
    for (let i = 1; i < newPageHeights.length; i++) {
      // 前一页的顶部位置 + 前一页的高度 + 页面间距
      this.pageTops[i] = this.pageTops[i-1] + newPageHeights[i-1] + PAGE_SPACING;
    }
    
    // 记录已加载的图片数量
    const loadedImagesCount = this.data.loadedImagesCount + 1;
    const imagesLoading = loadedImagesCount < this.data.imageUrls.length;
    
    this.setData({
      pageHeights: newPageHeights,
      scaleFactors: newScaleFactors,
      loadedImagesCount,
      imagesLoading
    }, () => {
      // 所有图片加载完成后，计算内容高度并初始化Canvas
      if (!imagesLoading) {
        this.calculateContentHeight();
        
        // 延迟初始化Canvas，确保DOM已更新
        setTimeout(() => {
          this.initPageCanvases();
          
          // 所有图片加载完成且Canvas初始化后，处理待处理的路径数据
          setTimeout(() => {
            if (this.pendingPathData && this.pendingPathData.length > 0) {
              console.log('图片加载完成，开始处理待处理的路径数据');
              this.processPathData(this.pendingPathData);
              this.pendingPathData = null; // 处理完成后清空
            }
          }, 500); // 再等待500ms确保Canvas完全初始化
        }, 300);
      }
    });
    
    console.log(`页面${index + 1}加载完成 - 尺寸: ${width}x${height}, 计算高度: ${pageHeight}px`);
    console.log(`页面${index + 1}原始尺寸: ${originalWidth}x${originalHeight}, 缩放因子: ${scaleFactor}`);
  },

  calculateContentHeight() {
    const totalHeight = this.data.pageHeights.reduce((acc, h) => acc + h + PAGE_SPACING, 0);
    const windowHeight = this.systemInfo ? this.systemInfo.windowHeight : 0;
    
    // 确保 movable-view 至少和窗口一样高，以防止垂直居中
    const contentHeight = Math.max(totalHeight, windowHeight);
    
    this.setData({ contentHeight: contentHeight });
    
    // 计算每页的顶部位置
    this.pageTops = this.data.pageHeights.map((h, i) => {
        return this.data.pageHeights.slice(0, i).reduce((sum, prevH) => sum + prevH + PAGE_SPACING, 0);
    });
    
    // 在内容高度计算完成后，初始化movable-area的位置
    setTimeout(() => {
      wx.createSelectorQuery().select('.movable-area').boundingClientRect(rect => {
        if (rect) {
          this.movableAreaTop = rect.top;
          this.movableAreaLeft = rect.left;
          console.log('初始化 movable-area 位置(calculateContentHeight):', { top: rect.top, left: rect.left });
        }
      }).exec();
    }, 100);
  },

  initPageCanvases() {
    this.data.imageUrls.forEach((_, index) => {
      wx.createSelectorQuery()
        .select(`#page-canvas-${index}`)
        .fields({ node: true, size: true })
        .exec((res) => {
          if (res[0] && res[0].node) {
            const canvas = res[0].node;
            const ctx = canvas.getContext('2d');
            const dpr = this.systemInfo.pixelRatio;
            canvas.width = res[0].width * dpr;
            canvas.height = res[0].height * dpr;
            ctx.scale(dpr, dpr);
            ctx.lineCap = 'round';
            ctx.lineJoin = 'round';
            this.pageCanvases[index] = { ctx, canvas };
            this.redrawAnnotations(index); // 如果有历史笔迹，则重绘
          }
        });
    });
  },
  
  initSigningCanvas() {
    wx.createSelectorQuery()
      .select('#signing-canvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        if (res[0] && res[0].node) {
          const canvas = res[0].node;
          const ctx = canvas.getContext('2d');
          const dpr = this.systemInfo.pixelRatio;
          
          // 设置画布物理像素大小，确保高清显示
          canvas.width = res[0].width * dpr;
          canvas.height = res[0].height * dpr;
          
          // 缩放绘图上下文，抵消高DPI带来的缩放
          ctx.scale(dpr, dpr);
          
          // 设置画笔样式
          ctx.lineCap = 'round';
          ctx.lineJoin = 'round';
          
          // 保存画布和上下文引用
          this.signingCanvas = canvas;
          this.signingContext = ctx;
          
          console.log(`签名画布初始化 - 尺寸: ${res[0].width}x${res[0].height}, DPR: ${dpr}`);
          console.log(`签名画布物理像素: ${canvas.width}x${canvas.height}`);
          
          // 获取当前页面的索引
          const currentPageIndex = this.data.currentPage - 1;
          
          // 获取当前页面的缩放因子
          const currentScaleFactor = this.data.scaleFactors[currentPageIndex] || 
                                    (A4_WIDTH_PT / this.data.availableWidth);
          
          console.log(`当前页面: ${this.data.currentPage}, 缩放因子: ${currentScaleFactor}`);
        }
      });
  },

  // 获取当前页面图片的边界
  getPageImageBounds(pageIndex) {
    wx.createSelectorQuery()
      .select(`.pdf-page:nth-child(${pageIndex + 1}) .bg-image`)
      .boundingClientRect(rect => {
        if (rect) {
          // 保存图片的位置和尺寸
          this.currentPageImageBounds = {
            left: rect.left,
            top: rect.top,
            right: rect.right,
            bottom: rect.bottom,
            width: rect.width,
            height: rect.height
          };
          
          console.log('当前页面图片边界:', this.currentPageImageBounds);
        }
      })
      .exec();
  },

  onViewChange(e) {
    // 移除 if 判断，确保任何来源(包括惯性、回弹)的视图变化都同步到 viewState
    this.viewState.x = e.detail.x;
    this.viewState.y = e.detail.y;
    this.updateCurrentPage();
  },

  onViewScale(e) {
    // 更新viewState
    const oldScale = this.viewState.scale;
    const newScale = e.detail.scale;
    
    this.viewState.scale = newScale;
    this.viewState.x = e.detail.x;
    this.viewState.y = e.detail.y;
    
    // 使用防抖更新scaleValue，避免频繁更新导致闪烁
    this.debouncedUpdateScale(newScale);
    
    // 更新当前页面
    this.updateCurrentPage();
    
    // 记录缩放变化
    if (Math.abs(newScale - oldScale) > 0.01) {
      console.log(`视图缩放变化: ${oldScale.toFixed(2)} -> ${newScale.toFixed(2)}`);
      
      // 获取当前页面索引
      const currentPageIndex = this.data.currentPage - 1;
      if (currentPageIndex >= 0) {
        // 获取当前页面的缩放因子
        const pageScaleFactor = this.data.scaleFactors[currentPageIndex];
        
        // 计算实际A4尺寸到屏幕的总缩放比例
        const totalScaleFactor = pageScaleFactor / newScale;
        
        console.log(`当前页面: ${this.data.currentPage}, A4缩放因子: ${pageScaleFactor}`);
        console.log(`总缩放比例: ${totalScaleFactor.toFixed(4)} (A4缩放因子 / 视图缩放)`);
      }
    }
  },
  
  updateCurrentPage() {
    const viewTop = -this.viewState.y / this.viewState.scale;
    let currentPage = 1;
    for (let i = 0; i < this.pageTops.length; i++) {
        const pageBottom = this.pageTops[i] + this.data.pageHeights[i];
        if (viewTop < pageBottom) {
            currentPage = i + 1;
            break;
        }
    }
    if (this.data.currentPage !== currentPage) {
      this.setData({ currentPage: currentPage });
    }
  },

  enterSigningMode() {
    // 检查是否是预览模式，预览模式下不允许进入签名状态
    const actionType = this.options.actionType || 'sign';
    if (actionType === 'preview') {
      wx.showToast({
        title: '预览模式不能进行签名',
        icon: 'none'
      });
      return;
    }
    
    // 检查用户是否已登录
    const openId = wx.getStorageSync('openId');
    const userInfo = wx.getStorageSync('userInfo');
    
    if (!openId || !userInfo || !userInfo.uid) {
      console.log('[PDF查看器] 用户未登录，显示登录框');
      
      // 如果已经有用户信息，但是不完整，复制到临时变量
      if (userInfo) {
        this.setData({
          tempUserInfo: {
            avatarUrl: userInfo.avatarUrl || '', // 确保avatarUrl至少是空字符串
            nickName: userInfo.nickName || '',
            uid: userInfo.uid || ''
          }
        });
      } else {
        // 如果未登录，使用默认值
        this.setData({
          tempUserInfo: {
            avatarUrl: '', // 使用空字符串而不是默认头像URL
            nickName: '',
            uid: ''
          }
        });
      }
      
      // 显示登录框
      this.setData({
        showLoginModal: true
      });
      
      // 动态设置导航栏的层级
      wx.setTabBarStyle({
        zIndex: 1
      });
      
      return; // 未登录，终止后续操作
    }
    
    // 用户已登录，继续进入签名模式
    // 获取所需的位置信息
    wx.createSelectorQuery()
      .select('.movable-area')
      .boundingClientRect(rect => {
        if (rect) {
          this.movableAreaTop = rect.top;
          this.movableAreaLeft = rect.left;
          console.log('进入签名模式 - movable-area位置:', { 
            top: rect.top, 
            left: rect.left,
            width: rect.width,
            height: rect.height
          });
          
          // 重置签名路径
          this.signingPaths = [];
          
          // 重置边界提示状态
          this.boundaryToastShown = false;
          
          // 进入签名模式
          this.setData({ 
            isSigning: true,
            showColorPanel: false, // 重置颜色面板状态
            pageIndicatorFlash: false // 重置页码指示器闪动状态
          }, () => {
            // 初始化签名画布
            setTimeout(() => {
              this.initSigningCanvas();
            }, 100);
          });
        }
      })
      .exec();
  },

  exitSigningMode() {
    this.projectSignature();
    
    // 重置边界提示状态
    this.boundaryToastShown = false;
    
    this.setData({ 
      isSigning: false,
      showColorPanel: false, // 确保颜色面板关闭
      pageIndicatorFlash: false // 重置页码指示器闪动状态
    });
    if (this.signingContext) {
      this.signingContext.clearRect(0, 0, this.signingCanvas.width, this.signingCanvas.height);
    }
  },

  startDrawing(e) {
    // 如果颜色面板打开，先关闭
    if (this.data.showColorPanel) {
      this.setData({ showColorPanel: false });
      return; // 阻止本次绘制开始
    }

    // 获取触摸点坐标（相对于屏幕）
    const { x: screenX, y: screenY } = e.touches[0];
    
    // 获取当前页面索引
    const currentPageIndex = this.data.currentPage - 1;
    
    // 获取当前视图状态
    const { scale, x: viewX, y: viewY } = this.viewState;
    
    // 计算相对于movable-area的坐标
    const areaX = screenX - this.movableAreaLeft;
    const areaY = screenY - this.movableAreaTop;
    
    // 计算相对于可滚动视图的坐标
    const contentX = (areaX - viewX) / scale;
    const contentY = (areaY - viewY) / scale;
    
    // 获取当前页面的顶部位置
    const pageTop = this.pageTops[currentPageIndex] || 0;
    
    // 关键修复：重新定义坐标系统
    // contentX 是相对于整个内容区域的坐标（包含左边距）
    // 我们需要计算相对于页面内容区域的坐标（不包含左边距）
    const leftMargin = this.pageLeftMargin || 0;
    const pageContentX = contentX - leftMargin; // 相对于页面内容区域的X坐标
    const pageContentY = contentY - pageTop; // 相对于页面内容区域的Y坐标
    
    // 检查点是否在页面边界内
    const pageWidth = this.data.availableWidth;
    const pageHeight = this.data.pageHeights[currentPageIndex] || 0;
    
    // 检查点是否在页面内容区域内
    console.log(`[坐标系统-详细] 触摸分析:`);
    console.log(`  屏幕坐标: (${screenX.toFixed(2)}, ${screenY.toFixed(2)})`);
    console.log(`  movable-area偏移: (${this.movableAreaLeft}, ${this.movableAreaTop})`);
    console.log(`  区域内坐标: (${areaX.toFixed(2)}, ${areaY.toFixed(2)})`);
    console.log(`  视图状态: scale=${scale}, offset=(${viewX}, ${viewY})`);
    console.log(`  内容坐标: (${contentX.toFixed(2)}, ${contentY.toFixed(2)})`);
    console.log(`  页面信息: top=${pageTop}, leftMargin=${leftMargin}, 页面尺寸=${pageWidth}x${pageHeight}`);
    console.log(`  页面内容坐标: (${pageContentX.toFixed(2)}, ${pageContentY.toFixed(2)})`);
    
    // 计算触摸点实际在哪个页面
    const touchPage = this.calculateTouchPage(contentY);
    const currentDisplayPage = this.data.currentPage;
    
    console.log(`[页面匹配检测] 触摸页面: ${touchPage}, 当前显示页面: ${currentDisplayPage}`);
    
    // 检查页面是否匹配
    if (touchPage !== currentDisplayPage) {
      console.log(`[页面匹配检测] 页面不匹配，需要滑动到第${touchPage}页`);
      
      // 防抖提示：避免频繁显示相同提示
      if (!this.boundaryToastShown) {
        this.boundaryToastShown = true;
        
        // 显示友好提示
        wx.showToast({
          title: `请完全滑动到第${touchPage}页进行签名`,
          icon: 'none',
          duration: 2000
        });
        
        // 触发页码指示器闪动
        this.triggerPageIndicatorFlash();
        
        // 2秒后重置提示状态
        setTimeout(() => {
          this.boundaryToastShown = false;
        }, 2000);
      }
      
      return;
    }
    
    // 严格的页面边界检查：仅允许在当前页面内开始绘制，超出则忽略
    if (pageContentX < -10 || pageContentX > pageWidth + 10 || 
        pageContentY < -5 || pageContentY > pageHeight + 5) {
      console.log('[坐标系统] 触摸点超出当前页面边界，忽略此次绘制');
      
      // 防抖提示：避免频繁显示相同提示
      if (!this.boundaryToastShown) {
        this.boundaryToastShown = true;
        wx.showToast({
          title: `请在第${currentPageIndex + 1}页进行签名`,
          icon: 'none',
          duration: 1500
        });
        
        // 1.5秒后重置提示状态
        setTimeout(() => {
          this.boundaryToastShown = false;
        }, 1500);
      }
      
      return;
    }
    
    // 使用当前页面的坐标
    const finalPageContentX = pageContentX;
    const finalPageContentY = pageContentY;
    
    // 设置为绘制状态
    this.setData({ isDrawing: true });
    
    // 初始化第一个点
    this.lastPoint = { 
      screenX, // 屏幕坐标用于画布绘制
      screenY,
      x: finalPageContentX, // 相对于页面内容区域的坐标，用于投影
      y: finalPageContentY,
      time: Date.now(), 
      width: this.data.penWidth,
      pageIndex: currentPageIndex
    };
    
    // 设置画笔样式
    this.signingContext.lineCap = 'round';
    this.signingContext.lineJoin = 'round';
    this.signingContext.strokeStyle = this.data.penColor;
    this.signingContext.fillStyle = this.data.penColor;

    // 创建新的笔迹路径并存储第一个点
    const newPath = [this.lastPoint];
    this.signingPaths.push(newPath);

    // 使用屏幕坐标在签名画布上绘制
    this.signingContext.beginPath();
    this.signingContext.arc(screenX, screenY, this.data.penWidth / 2, 0, 2 * Math.PI);
    this.signingContext.fill();
    
    console.log(`[坐标系统] 开始绘制 - 屏幕位置: (${screenX.toFixed(2)}, ${screenY.toFixed(2)}), 页面内容位置: (${finalPageContentX.toFixed(2)}, ${finalPageContentY.toFixed(2)}), 当前页面: ${currentPageIndex + 1}`);
  },

  draw(e) {
    // 如果不在绘制状态，直接返回
    if (!this.data.isDrawing) return;
    
    // 获取当前触摸点坐标（相对于屏幕）
    const { x: screenX, y: screenY } = e.touches[0];
    
    // 获取当前页面索引
    const currentPageIndex = this.data.currentPage - 1;
    
    // 获取当前视图状态
    const { scale, x: viewX, y: viewY } = this.viewState;
    
    // 计算相对于movable-area的坐标
    const areaX = screenX - this.movableAreaLeft;
    const areaY = screenY - this.movableAreaTop;
    
    // 计算相对于可滚动视图的坐标
    const contentX = (areaX - viewX) / scale;
    const contentY = (areaY - viewY) / scale;
    
    // 获取当前页面的顶部位置
    const pageTop = this.pageTops[currentPageIndex] || 0;
    
    // 关键修复：重新定义坐标系统
    const leftMargin = this.pageLeftMargin || 0;
    const pageContentX = contentX - leftMargin; // 相对于页面内容区域的X坐标
    const pageContentY = contentY - pageTop; // 相对于页面内容区域的Y坐标
    
    // 检查点是否在页面边界内
    const pageWidth = this.data.availableWidth;
    const pageHeight = this.data.pageHeights[currentPageIndex] || 0;
    
    // 严格的页面边界检查：仅允许在当前页面内绘制，超出则停止
    if (pageContentX < -10 || pageContentX > pageWidth + 10 || 
        pageContentY < -5 || pageContentY > pageHeight + 5) {
      // 如果超出当前页面边界，停止当前绘制
      this.stopDrawing();
      console.log('[坐标系统] 触摸点超出当前页面边界，停止绘制');
      
      // 防抖提示：避免频繁显示相同提示
      if (!this.boundaryToastShown) {
        this.boundaryToastShown = true;
        wx.showToast({
          title: `请在第${currentPageIndex + 1}页进行签名`,
          icon: 'none',
          duration: 1500
        });
        
        // 1.5秒后重置提示状态
        setTimeout(() => {
          this.boundaryToastShown = false;
        }, 1500);
      }
      
      return;
    }
    
    // 计算触摸点实际在哪个页面（简化版本，仅在超出边界时检查）
    const touchPage = this.calculateTouchPage(contentY);
    const currentDisplayPage = this.data.currentPage;
    
    // 如果页面不匹配，停止绘制并提示
    if (touchPage !== currentDisplayPage) {
      console.log(`[页面匹配检测-绘制中] 页面不匹配: 触摸页面${touchPage} vs 显示页面${currentDisplayPage}`);
      
      // 停止当前绘制
      this.stopDrawing();
      
      // 防抖提示：避免频繁显示相同提示
      if (!this.boundaryToastShown) {
        this.boundaryToastShown = true;
        
        wx.showToast({
          title: `请完全滑动到第${touchPage}页进行签名`,
          icon: 'none',
          duration: 2000
        });
        
        // 触发页码指示器闪动
        this.triggerPageIndicatorFlash();
        
        // 2秒后重置提示状态
        setTimeout(() => {
          this.boundaryToastShown = false;
        }, 2000);
      }
      
      return;
    }
    
    // 使用当前页面的坐标
    const finalPageContentX = pageContentX;
    const finalPageContentY = pageContentY;
    
    const currentTime = Date.now();
    const lastPoint = this.lastPoint;
    
    // 计算距离和时间差（使用屏幕坐标计算）
    const deltaTime = currentTime - lastPoint.time;
    const distance = Math.sqrt(
      Math.pow(screenX - lastPoint.screenX, 2) + 
      Math.pow(screenY - lastPoint.screenY, 2)
    );
    
    // 计算速度和笔宽
    const speed = deltaTime > 0 ? distance / deltaTime : 0;
    const speedThreshold = 1.2; // 速度阈值，可调整
    const speedFactor = Math.max(0, 1 - speed / speedThreshold);
    
    // 根据速度计算笔宽 - 速度越快，笔画越细
    let currentWidth = this.data.minPenWidth + 
                      (this.data.penWidth - this.data.minPenWidth) * speedFactor;

    // 平滑宽度变化，避免突变（70%上一点宽度 + 30%当前计算宽度）
    currentWidth = (lastPoint.width * 0.7) + (currentWidth * 0.3);

    // 创建当前点并记录
    const currentPoint = { 
      screenX, // 屏幕坐标用于画布绘制
      screenY,
      x: finalPageContentX, // 相对于页面内容区域的坐标，用于投影
      y: finalPageContentY,
      time: currentTime, 
      width: currentWidth,
      pageIndex: currentPageIndex
    };

    // 同一页面内，正常绘制连接线
    this.signingContext.beginPath();
    this.signingContext.moveTo(lastPoint.screenX, lastPoint.screenY);
    this.signingContext.lineWidth = currentWidth;
    this.signingContext.lineTo(screenX, screenY);
    this.signingContext.stroke();
    
    // 将点添加到当前路径
    const currentPath = this.signingPaths[this.signingPaths.length - 1];
    currentPath.push(currentPoint);
    
    // 更新最后一个点
    this.lastPoint = currentPoint;
    
    // 如果移动距离较大，记录调试信息
    if (distance > 20) {
      console.log(`[坐标系统] 绘制中 - 屏幕距离: ${distance.toFixed(2)}px, 速度: ${speed.toFixed(2)}px/ms, 笔宽: ${currentWidth.toFixed(2)}`);
      console.log(`[坐标系统] 当前点 - 屏幕: (${screenX.toFixed(2)}, ${screenY.toFixed(2)}), 页面内容: (${finalPageContentX.toFixed(2)}, ${finalPageContentY.toFixed(2)}), 当前页面: ${currentPageIndex + 1}`);
    }
  },
  
  stopDrawing(e) {
    // 检查是否在绘制状态，如果不是则无需处理
    if (!this.data.isDrawing) return;
    
    this.setData({ isDrawing: false });
    this.lastPoint = null;
  },
  
  // 处理触摸取消事件
  handleTouchCancel() {
    // 简单地结束绘制，不尝试取消事件
    if (this.data.isDrawing) {
      this.setData({ isDrawing: false });
      this.lastPoint = null;
    }
  },
  
  projectSignature() {
    // 如果没有笔迹，直接返回
    if (this.signingPaths.length === 0 || this.signingPaths.every(p => p.length === 0)) return;

    console.log('========== 签名投影开始 ==========');
    
    // 获取视图状态
    const { scale, x: viewX, y: viewY } = this.viewState;
    
    console.log('[坐标系统] 视图状态:', { scale, x: viewX, y: viewY });
    
    // 按页面索引对笔迹进行分组
    const pathsByPage = {};
    
    // 遍历所有笔迹路径
    this.signingPaths.forEach(path => {
      if (path.length === 0) return;
      
      // 获取第一个点的页面索引
      const pageIndex = path[0].pageIndex;
      
      // 如果该页面还没有路径数组，创建一个
      if (!pathsByPage[pageIndex]) {
        pathsByPage[pageIndex] = [];
      }
      
      // 将路径添加到对应页面的数组中
      pathsByPage[pageIndex].push(path);
    });
    
    console.log('[坐标系统] 按页面分组的笔迹:', Object.keys(pathsByPage));
    
    // 处理每个页面的笔迹
    for (const pageIndex in pathsByPage) {
      if (pathsByPage.hasOwnProperty(pageIndex)) {
        const pagePathList = pathsByPage[pageIndex];
        const scaleFactor = this.data.scaleFactors[pageIndex] || 1;
        const pageWidth = this.data.availableWidth || 0;
        
        console.log(`[坐标系统] 处理页面${parseInt(pageIndex) + 1}的笔迹，共${pagePathList.length}条，缩放因子:${scaleFactor}, 页面宽度:${pageWidth}`);
        
        // 转换该页面的所有笔迹
        const transformedPaths = pagePathList.map(path => {
          const convertedPoints = [];
          
          path.forEach(point => {
            // 关键修复：现在point.x和point.y已经是相对于页面内容区域的坐标
            // 不需要再减去左边距，直接转换为A4坐标
            const a4X = point.x * scaleFactor;
            const a4Y = point.y * scaleFactor;
            
            // 记录调试信息
            if (point === path[0]) {
              console.log(`[坐标系统] 坐标转换: 页面内容坐标(${point.x.toFixed(2)}, ${point.y.toFixed(2)}) -> ` +
                         `A4坐标(${a4X.toFixed(2)}, ${a4Y.toFixed(2)}), A4宽度: ${A4_WIDTH_PT}`);
            }
            
            // 检查坐标是否在A4边界内
            if (a4X >= -10 && a4X <= A4_WIDTH_PT + 10 && a4Y >= -10 && a4Y <= A4_HEIGHT_PT + 10) {
              // 确保坐标在A4范围内
              const clampedX = Math.max(0, Math.min(a4X, A4_WIDTH_PT));
              const clampedY = Math.max(0, Math.min(a4Y, A4_HEIGHT_PT));
              
              // 如果坐标被钳制，记录日志
              if (clampedX !== a4X || clampedY !== a4Y) {
                console.log(`[坐标系统] 点(${a4X.toFixed(2)}, ${a4Y.toFixed(2)})超出A4边界，被钳制为(${clampedX.toFixed(2)}, ${clampedY.toFixed(2)})`);
              }
              
              convertedPoints.push({
                x: clampedX,
                y: clampedY,
                width: point.width * scaleFactor // 笔宽也需要转换
              });
            } else {
              console.log(`[坐标系统] 点(${a4X.toFixed(2)}, ${a4Y.toFixed(2)})超出A4边界，已被过滤`);
            }
          });
          
          if (convertedPoints.length > 0) {
            return {
              color: this.data.penColor,
              points: convertedPoints
            };
          }
          return null; // 如果路径中所有点都不在页面内
        }).filter(p => p !== null); // 过滤掉空路径
        
        // 如果没有有效的笔迹，跳过该页面
        if (transformedPaths.length === 0) {
          console.log(`[坐标系统] 页面${parseInt(pageIndex) + 1}没有有效的笔迹需要投影`);
          continue;
        }
        
        // 保存转换后的路径到对应页面
        const newAllPaths = { ...this.data.allPaths };
        const existingPaths = newAllPaths[pageIndex] || [];
        newAllPaths[pageIndex] = existingPaths.concat(transformedPaths);
        
        this.setData({
          allPaths: newAllPaths,
        });
        
        // 重绘当前页面的所有笔迹
        this.redrawAnnotations(parseInt(pageIndex));
        
        console.log(`[坐标系统] 页面${parseInt(pageIndex) + 1}笔迹投影完成，共${transformedPaths.length}条`);
      }
    }
    
    console.log('========== 签名投影结束 ==========');
  },
  
  redrawAnnotations(index) {
    // 获取页面Canvas上下文
    const { ctx, canvas } = this.pageCanvases[index] || {};
    if (!ctx || !canvas) {
      console.log(`页面${index + 1}的Canvas未初始化，无法绘制`);
      return;
    }
    
    // 清除画布
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 获取页面的笔迹
    const paths = this.data.allPaths[index] || [];
    if (paths.length === 0) {
      return; // 没有笔迹，直接返回
    }
    
    // 获取当前页面的缩放因子
    const scaleFactor = this.data.scaleFactors[index] || 1;
    const leftMargin = this.pageLeftMargin || 0;
    
    console.log(`[坐标系统-重绘] 页面${index + 1}重绘分析:`);
    console.log(`  路径数: ${paths.length}`);
    console.log(`  缩放因子: ${scaleFactor}`);
    console.log(`  左边距: ${leftMargin}`);
    
    // 遍历所有笔迹路径
    paths.forEach((path, pathIndex) => {
      // 设置绘制样式
      ctx.strokeStyle = path.color;
      ctx.fillStyle = path.color;
      ctx.lineCap = 'round';
      ctx.lineJoin = 'round';

      // 检查路径是否有效
      if (!path.points || path.points.length < 1) return;
      
      // 分析第一个点的坐标转换
      if (pathIndex === 0) {
        const firstA4Point = path.points[0];
        console.log(`[坐标系统-重绘] 路径${pathIndex + 1}第一个点分析:`);
        console.log(`  A4坐标: (${firstA4Point.x.toFixed(2)}, ${firstA4Point.y.toFixed(2)})`);
        
        // 转换过程
        const contentX = firstA4Point.x / scaleFactor;
        const contentY = firstA4Point.y / scaleFactor;
        console.log(`  转换为内容坐标: (${contentX.toFixed(2)}, ${contentY.toFixed(2)})`);
        
        // 关键问题检查：我们是否应该加回左边距？
        // 页面Canvas的坐标系统是什么？
        // 让我们尝试不加左边距，看看结果
        const canvasX = contentX; // 不加左边距试试
        const canvasY = contentY;
        console.log(`  最终Canvas坐标(不加边距): (${canvasX.toFixed(2)}, ${canvasY.toFixed(2)})`);
        
        const canvasXWithMargin = contentX + leftMargin; // 加左边距
        console.log(`  最终Canvas坐标(加边距): (${canvasXWithMargin.toFixed(2)}, ${canvasY.toFixed(2)})`);
      }
      
      // 将A4坐标转换为Canvas坐标
      const canvasPoints = path.points.map(point => {
        // 从A4坐标系转换回页面内容坐标系
        const contentX = point.x / scaleFactor;
        const contentY = point.y / scaleFactor;
        
        // 关键修复：尝试不添加页面左边距
        // 因为页面Canvas可能已经定位在正确的位置
        return {
          x: contentX, // 不加左边距
          y: contentY,
          width: point.width / scaleFactor
        };
      });
      
      // 绘制第一个点
      const firstPoint = canvasPoints[0];
      
      ctx.beginPath();
      ctx.arc(firstPoint.x, firstPoint.y, firstPoint.width / 2, 0, 2 * Math.PI);
      ctx.fill();

      // 逐段绘制线条
      for (let i = 0; i < canvasPoints.length - 1; i++) {
        const p1 = canvasPoints[i];
        const p2 = canvasPoints[i + 1];
        
        ctx.beginPath();
        ctx.moveTo(p1.x, p1.y);
        ctx.lineWidth = (p1.width + p2.width) / 2; // 使用平均宽度使过渡平滑
        ctx.lineTo(p2.x, p2.y);
        ctx.stroke();
      }
    });
  },

  // 切换颜色选择面板的显示状态
  toggleColorPicker() {
    this.setData({
      showColorPanel: !this.data.showColorPanel
    });
  },

  // 改变画笔颜色
  changePenColor(e) {
    const color = e.currentTarget.dataset.color;
    this.setData({
      penColor: color,
      showColorPanel: false // 选择颜色后自动关闭面板
    });
  },

  clearSignature() {
    // 清除当前签名会话的所有笔迹
    this.signingPaths = [];
    
    // 清除签名画布
    if (this.signingContext && this.signingCanvas) {
      const width = this.signingCanvas.width / this.systemInfo.pixelRatio;
      const height = this.signingCanvas.height / this.systemInfo.pixelRatio;
      this.signingContext.clearRect(0, 0, width, height);
      
      console.log('签名已清除');
    } else {
      console.log('签名画布未初始化，无法清除');
    }
  },

  savePdf() {
    // 获取新添加的路径数据，排除初始加载的数据
    const output = [];
    const allPaths = this.data.allPaths;
    const initialPaths = this.data.initialPaths;

    for (const pageIndex in allPaths) {
      // 确保是有效页面且有签名
      if (allPaths.hasOwnProperty(pageIndex) && allPaths[pageIndex].length > 0) {
        const pageIdx = parseInt(pageIndex, 10);
        const scaleFactor = this.data.scaleFactors[pageIdx] || 1;
        
        // 获取该页面的初始路径
        const pageInitialPaths = initialPaths[pageIndex] || [];
        
        // 筛选出新添加的路径（不在初始路径中的）
        const newPaths = allPaths[pageIndex].filter(newPath => {
          // 检查是否是新添加的路径
          return !pageInitialPaths.some(initialPath => {
            // 检查路径是否相同
            if (initialPath.color !== newPath.color || 
                initialPath.points.length !== newPath.points.length) {
              return false; // 颜色或点数不同，肯定是不同的路径
            }
            
            // 深度比较路径中的点
            for (let i = 0; i < initialPath.points.length; i++) {
              const ip = initialPath.points[i];
              const np = newPath.points[i];
              // 比较x、y坐标，允许一些微小的浮点误差
              if (Math.abs(ip.x - np.x) > 0.5 || Math.abs(ip.y - np.y) > 0.5) {
                return false; // 坐标不匹配，是不同的路径
              }
            }
            return true; // 所有点都匹配，认为是同一条路径
          });
        });
        
        // 如果没有新添加的路径，跳过这个页面
        if (newPaths.length === 0) {
          console.log(`页面${pageIdx + 1}没有新添加的路径，跳过该页面`);
          continue;
        }
        
        console.log(`页面${pageIdx + 1}有${newPaths.length}条新添加的路径，准备上传`);
        
        const pageData = {
          pageNumber: pageIdx + 1,
          paths: []
        };
        
        // 遍历该页的每一条笔迹（仅处理新添加的）
        newPaths.forEach(path => {
          // allPaths中的坐标已经是最终的A4坐标，直接使用
          for (let i = 0; i < path.points.length - 1; i++) {
            const p1 = path.points[i];
            const p2 = path.points[i + 1];
            
            pageData.paths.push({
              x1: p1.x,
              y1: p1.y,
              x2: p2.x,
              y2: p2.y,
              color: path.color,
              width: (p1.width + p2.width) / 2 // 笔宽也已经是A4尺寸下的宽度
            });
          }
        });

        if (pageData.paths.length > 0) {
            output.push(pageData);
        }
      }
    }

    if (output.length === 0) {
      wx.showToast({ title: '没有检测到新增签名', icon: 'none' });
      return;
    }

    const signatureData = JSON.stringify(output, null, 2);
    console.log('生成的轨迹数据:', signatureData);
    
    // 调用接口上传轨迹数据
    wx.showLoading({
      title: '保存中...',
    });
    
    // 获取文档ID
    const pdfId = this.options.pdfId || '';
    
    // 上传轨迹数据
    api.article.uploadPath({
      id: pdfId,
      pathData: output,
      openId: wx.getStorageSync('openId') || ''
    }).then(res => {
      wx.hideLoading();
      wx.showToast({
        title: '保存成功',
        icon: 'success'
      });
      
      // 保存成功后，将当前所有路径设置为初始路径，以便下次只上传新增内容
      this.setData({
        initialPaths: JSON.parse(JSON.stringify(this.data.allPaths))
      });
      
      // 返回上一页
      setTimeout(() => {
        wx.navigateBack({
          delta: 1
        });
      }, 1500);
    }).catch(err => {
      wx.hideLoading();
      console.error('上传轨迹数据失败:', err);
      
      // 显示具体的错误信息
      if (err && err.msg) {
        wx.showToast({
          title: err.msg,
          icon: 'none'
        });
      } else {
        wx.showToast({
          title: '保存失败',
          icon: 'none'
        });
      }
    });
  },

  // 分享配置
  onShareAppMessage() {
    // 获取文档ID
    const pdfId = this.options.pdfId || '';
    
    // 构建完整的分享路径
    let path = `/pages/pdf-viewer/pdf-viewer?pdfId=${pdfId}&isshare=1`;
    
    // 使用文档标题作为分享标题，如果没有则使用默认标题
    const shareTitle = this.data.documentTitle || '查看文档';
    
    return {
      title: shareTitle,
      path: path,
      imageUrl: this.data.imageUrls[0] || '/assets/images/share_default.png' // 使用第一页作为分享图片
    };
  },





  // 添加防抖函数
  debounce(fn, delay = 100) {
    let timer = null;
    return function(...args) {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        fn.apply(this, args);
      }, delay);
    };
  },

  // 计算触摸点所在的页面
  calculateTouchPage(contentY) {
    for (let i = 0; i < this.data.imageUrls.length; i++) {
      const pageTop = this.pageTops[i] || 0;
      const pageHeight = this.data.pageHeights[i] || 0;
      const pageBottom = pageTop + pageHeight;
      
      if (contentY >= pageTop && contentY <= pageBottom) {
        return i + 1; // 返回页码（从1开始）
      }
    }
    
    // 如果没有精确匹配，返回最接近的页面
    let minDistance = Infinity;
    let closestPage = 1;
    
    for (let i = 0; i < this.data.imageUrls.length; i++) {
      const pageTop = this.pageTops[i] || 0;
      const pageHeight = this.data.pageHeights[i] || 0;
      const pageCenter = pageTop + pageHeight / 2;
      const distance = Math.abs(contentY - pageCenter);
      
      if (distance < minDistance) {
        minDistance = distance;
        closestPage = i + 1;
      }
    }
    
    return closestPage;
  },

  // 触发页码指示器闪动
  triggerPageIndicatorFlash() {
    this.setData({ pageIndicatorFlash: true });
    
    // 6秒后关闭闪动效果（3次闪动 * 2秒）
    setTimeout(() => {
      this.setData({ pageIndicatorFlash: false });
    }, 6000);
  },

  // 从API加载文档数据（图片列表和路径数据）
  loadDocumentData(pdfId) {
    wx.showLoading({
      title: '加载文档...',
    });
    
    // 判断用户是否已登录
    const openId = wx.getStorageSync('openId');
    
    // 获取操作类型
    const actionType = this.options.actionType || 'sign';
    console.log('文档操作类型:', actionType);
    
    // 构建请求参数
    const params = { id: pdfId };
    
    // 根据操作类型设置 signType（必传）
    let signType = 1; // 默认预览
    if (actionType === 'preview') {
      signType = 1; // 预览文档
    } else if (actionType === 'resign') {
      signType = 2; // 重新签名
    } else if (actionType === 'sign') {
      signType = 1; // 初次签名按预览处理
    }
    params.signType = signType;
    
    // 只要有 openId 就必须传递
    if (openId) {
      console.log('用户已登录，传入openId参数:', openId, 'signType:', signType);
      params.openId = openId;
    } else {
      console.log('用户未登录，不传入openId参数，signType:', signType);
    }
    
    api.article.getArticleImg(params)
      .then(res => {
        wx.hideLoading();
        console.log('获取文档数据成功，完整响应:', res);
        
        // 保存签名模式、文档标题、文件ID和openId
        const signModel = res.signModel ? parseInt(res.signModel) : 1;
        const fileName = res.fileName || '未知文档';
        const fileId = res.fileId || res.id || ''; // 尝试获取fileId，如果没有则使用id
        const articleOpenId = res.openId; // 保存getArticleImg返回的openId
        
        this.setData({ 
          signModel: signModel,
          documentTitle: fileName,
          fileId: fileId,
          articleOpenId: articleOpenId // 保存openId供导出时使用
        });
        
        // 接口返回的是图片数组
        const imageData = res.articleImgList || [];
        console.log('图片数组数据:', imageData);
        
        if (imageData && imageData.length > 0) {
          // 从request.js导入的IMG_URL常量构建完整的图片URL列表
          console.log('使用的IMG_URL:', IMG_URL); // 打印检查IMG_URL
          
          // 打印第一个图片数据的详细信息
          console.log('第一个图片数据详情:', imageData[0]);
          
          const imageUrls = imageData.map(item => {
            // 检查fileName是否存在
            if (!item.fileName) {
              console.error('图片数据缺少fileName字段:', item);
              return null;
            }
            const fullUrl = IMG_URL + item.fileName;
            console.log('构建的完整图片URL:', fullUrl);
            return fullUrl;
          }).filter(url => url !== null); // 过滤掉无效的URL
          
          // 检查是否有有效的图片URL
          if (imageUrls.length === 0) {
            console.error('没有有效的图片URL');
            wx.showToast({
              title: '文档图片加载失败',
              icon: 'none'
            });
            // 加载测试图片
            this.loadImages({});
            return;
          }
          
          // 设置图片URL列表
          const pageHeights = new Array(imageUrls.length).fill(0);
          const scaleFactors = new Array(imageUrls.length).fill(1); // 默认缩放因子为1
          const allPaths = {};
          imageUrls.forEach((_, index) => {
            allPaths[index] = [];
          });
          
          this.setData({
            imageUrls: imageUrls,
            pageHeights: pageHeights,
            originalWidths: new Array(imageUrls.length).fill(0),
            originalHeights: new Array(imageUrls.length).fill(0),
            scaleFactors: scaleFactors,
            allPaths: allPaths,
            imagesLoading: true, // 重置图片加载状态为加载中
            loadedImagesCount: 0 // 重置已加载图片计数
          });
          
          // 如果返回数据中包含路径数据，处理签名路径
          if (res.articleImgPathList && res.articleImgPathList.length > 0) {
            // 等待图片加载完成后再处理路径数据
            this.pendingPathData = res.articleImgPathList;
            // 在图片加载完成后会自动处理路径数据
          }
        } else {
          wx.showToast({
            title: '文档内容为空',
            icon: 'none'
          });
          // 加载测试图片
          this.loadImages({});
        }
      })
      .catch(err => {
        wx.hideLoading();
        console.error('获取文档数据失败:', err);
        wx.showToast({
          title: '获取文档失败',
          icon: 'none'
        });
        // 加载测试图片
        this.loadImages({});
      });
  },

  // 切换签署信息弹框的显示状态
  toggleSignatureInfo() {
    const nextState = !this.data.showSignatureInfo;
    this.setData({
      showSignatureInfo: nextState
    });

    // 如果是打开弹窗，并且列表为空，则获取数据
    if (nextState && this.data.signatureList.length === 0) {
      this.fetchSignatureInfo();
    }
  },

  fetchSignatureInfo() {
    const pdfId = this.options.pdfId;
    if (!pdfId) {
      toast.showToast('缺少文档ID，无法获取签署信息');
      return;
    }

    wx.showLoading({ title: '加载中...' });

    api.article.getSignInfo(pdfId).then(res => {
      wx.hideLoading();
      console.log('[调试] getSignInfo 原始响应数据:', res);
      console.log('[调试] 响应数据类型:', typeof res, '是否为数组:', Array.isArray(res));
      
      if (res && Array.isArray(res)) {
        console.log('[调试] 签名列表长度:', res.length);
        
        // 打印每一行的详细信息
        res.forEach((item, index) => {
          console.log(`[调试] 第${index + 1}行原始数据:`, item);
          console.log(`[调试] 第${index + 1}行 - id: ${item.id}, openId: ${item.openId}, nickName: ${item.nickName}`);
        });
        
        const formattedList = res.map((item, index) => {
          // 格式化时间，去掉年份
          let formattedTime = item.createTime || '';
          if (formattedTime) {
            // 假设时间格式为 "YYYY-MM-DD HH:mm:ss"
            const timeMatch = formattedTime.match(/\d{4}-(\d{2}-\d{2} \d{2}:\d{2}):\d{2}/);
            if (timeMatch && timeMatch[1]) {
              formattedTime = timeMatch[1]; // 只保留 "MM-DD HH:mm"
            }
          }
          
          const formattedItem = {
            ...item,
            // 格式化头像URL，如果不存在则使用默认头像
            avatarUrl: item.avatarUrl ? IMG_URL + item.avatarUrl : defaultAvatarUrl,
            // 格式化昵称，如果不存在则使用真实姓名
            nickName: item.nickName || item.realName || '匿名用户',
            // 使用格式化后的时间
            createTime: formattedTime
          };
          
          console.log(`[调试] 第${index + 1}行格式化后数据:`, formattedItem);
          console.log(`[调试] 第${index + 1}行格式化后 - id: ${formattedItem.id}, openId: ${formattedItem.openId}, nickName: ${formattedItem.nickName}`);
          
          return formattedItem;
        });
        
        console.log('[调试] 最终设置的 signatureList:', formattedList);
        
        this.setData({
          signatureList: formattedList
        });
      } else {
        console.log('[调试] 响应数据不是数组或为空，设置空列表');
        this.setData({ signatureList: [] });
      }
    }).catch(err => {
      wx.hideLoading();
      toast.showToast('加载签署信息失败');
      console.error('[SignatureInfo] Fetch failed:', err);
    });
  },

  processPathData(pathDataList) {
    // 确保页面Canvas已经初始化
    const checkCanvasAndProcess = () => {
      const allInitialized = Object.keys(this.pageCanvases).length === this.data.imageUrls.length;
      if (allInitialized) {
        this._processPathData(pathDataList);
      } else {
        // 如果Canvas还没准备好，等100ms再检查
        setTimeout(checkCanvasAndProcess, 100);
      }
    };
    
    checkCanvasAndProcess();
  },
  
  // 实际处理路径数据的函数
  _processPathData(pathDataList) {
    console.log('开始处理路径数据，共有', pathDataList.length, '条数据');
    
    // 确保initialPaths对象已初始化
    if (!this.data.initialPaths) {
      const initialPaths = {};
      this.data.imageUrls.forEach((_, index) => {
        initialPaths[index] = [];
      });
      this.setData({ initialPaths });
    }
    
    // 遍历所有路径数据
    pathDataList.forEach((pathData, idx) => {
      try {
        console.log(`处理第${idx+1}条路径数据，字段:`, Object.keys(pathData));
        
        // 根据OP提供的格式，paths可能在不同的字段中
        let pathsStr = null;
        
        // 尝试直接获取paths字段
        if (pathData.paths) {
          pathsStr = pathData.paths;
          console.log('找到paths字段');
        }
        
        // 如果paths字段中没有数据，尝试根据OP示例格式查找
        if (!pathsStr) {
          console.log('尝试查找其他可能包含路径的字段');
          const keys = Object.keys(pathData);
          
          // 查找可能包含路径数据的字段
          for (const key of keys) {
            const value = pathData[key];
            console.log(`检查字段 ${key}, 类型:`, typeof value);
            
            if (typeof value === 'string' && 
                (value.includes('x1') || value.includes('color') || value.includes('width'))) {
              console.log(`字段 ${key} 可能包含路径数据`);
              pathsStr = value;
              break;
            }
          }
        }
        
        // 如果找不到路径数据，跳过处理
        if (!pathsStr) {
          console.log('未找到有效的路径数据字段，跳过处理');
          return;
        }
        
        // 获取页码，默认为第1页
        const pageNumber = pathData.pageNumber ? parseInt(pathData.pageNumber) : 1;
        const pageIndex = pageNumber - 1;
        
        if (pageIndex < 0 || pageIndex >= this.data.imageUrls.length) {
          console.log(`页码${pageNumber}超出范围，图片总数:${this.data.imageUrls.length}`);
          return;
        }
        
        // 解析路径字符串
        let pathsArray = [];
        try {
          console.log('尝试解析路径数据字符串，前100个字符:', pathsStr.substring(0, 100) + '...');
          pathsArray = JSON.parse(pathsStr);
          
          if (!Array.isArray(pathsArray)) {
            console.error('解析后的路径数据不是数组:', typeof pathsArray);
            return;
          }
          
          console.log(`解析成功，路径数据中包含${pathsArray.length}个点`);
          
          // 检查第一个点的结构
          if (pathsArray.length > 0) {
            const firstPoint = pathsArray[0];
            console.log('第一个点结构:', firstPoint);
            
            // 验证点的格式是否符合要求
            if (!firstPoint.x1 || !firstPoint.y1 || !firstPoint.x2 || !firstPoint.y2) {
              console.warn('点结构可能不符合要求，尝试适配处理');
            }
          }
        } catch (parseError) {
          console.error('解析路径数据失败:', parseError);
          return;
        }
        
        // 转换路径格式为Canvas所需格式
        const transformedPaths = this._transformPathsToCanvasFormat(pathsArray, pageIndex);
        console.log(`转换完成，生成了${transformedPaths.length}条绘制路径`);
        
        // 更新allPaths中对应页面的路径
        const newAllPaths = { ...this.data.allPaths };
        const existingPaths = newAllPaths[pageIndex] || [];
        newAllPaths[pageIndex] = existingPaths.concat(transformedPaths);
        
        // 同时将这些路径记录为初始路径
        const newInitialPaths = { ...this.data.initialPaths };
        newInitialPaths[pageIndex] = (newInitialPaths[pageIndex] || []).concat(transformedPaths);
        
        this.setData({
          allPaths: newAllPaths,
          initialPaths: newInitialPaths
        }, () => {
          // 重绘当前页面的注释
          console.log(`重绘页面${pageIndex + 1}的路径`);
          this.redrawAnnotations(pageIndex);
        });
      } catch (error) {
        console.error('处理路径数据异常:', error);
        if (pathData) {
          console.error('原始数据字段:', Object.keys(pathData));
        }
      }
    });
  },
  
  // 转换路径格式
  _transformPathsToCanvasFormat(paths, pageIndex) {
    if (!paths || paths.length === 0) {
      return [];
    }
    
    // 获取当前页面的缩放比例
    const scaleFactor = this.data.scaleFactors[pageIndex] || 1;
    
    console.log(`页面${pageIndex + 1} - 转换路径数据，缩放因子:${scaleFactor}`);
    
    // 检查路径数据的格式
    const samplePoint = paths[0];
    console.log('样本点:', samplePoint);
    
    // 确认是否是OP提供的特定格式 - {x1,y1,x2,y2,color,width}
    const isOpFormat = samplePoint && 
                      samplePoint.hasOwnProperty('x1') && 
                      samplePoint.hasOwnProperty('y1') && 
                      samplePoint.hasOwnProperty('x2') && 
                      samplePoint.hasOwnProperty('y2');
                      
    console.log('是否为OP特定格式:', isOpFormat);
    
    // 转换路径
    const transformedPaths = [];
    
    if (isOpFormat) {
      // 使用专门的处理方法处理OP格式
      return this._transformOpFormatPaths(paths, pageIndex, scaleFactor);
    } else {
      // 使用通用处理方法
      let currentPath = null;
      let lastPoint = null;
      
      // 处理通用格式的路径
      paths.forEach((point, index) => {
        // 检查是否需要创建新路径
        if (!currentPath || !lastPoint) {
          // 创建新路径
          currentPath = {
            color: 'black', // 默认颜色
            points: []
          };
          
          // 添加第一个点，PDF坐标转换为Canvas坐标
          // 注意：API返回的路径数据是A4坐标系的，我们只需要存储原始A4坐标
          // 不需要减去页面左边距，因为在redrawAnnotations中会正确处理
          currentPath.points.push({
            x: point.x,
            y: point.y,
            width: point.width || 3
          });
          
          transformedPaths.push(currentPath);
        } else {
          // 添加后续点，PDF坐标转换为Canvas坐标
          currentPath.points.push({
            x: point.x,
            y: point.y,
            width: point.width || 3
          });
        }
        
        // 更新最后一个点
        lastPoint = point;
      });
    }
    
    return transformedPaths;
  },
  
  // 专门处理OP提供的特定格式路径数据
  _transformOpFormatPaths(paths, pageIndex, scaleFactor) {
    const transformedPaths = [];
    let currentPath = null;
    let lastPoint = null;
    
    console.log(`处理OP特定格式路径，点数:${paths.length}`);
    
    // 对OP格式的路径进行分组处理
    paths.forEach((segment, index) => {
      // 获取颜色和宽度
      const color = segment.color || 'black';
      const width = segment.width || 3;
      
      // 检查是否需要创建新路径
      // 如果是第一个点，或者与前一个点不连续，或者颜色/宽度变化，则创建新路径
      if (!currentPath || !lastPoint || 
          Math.abs(lastPoint.x2 - segment.x1) > 0.5 || 
          Math.abs(lastPoint.y2 - segment.y1) > 0.5 || 
          lastPoint.color !== color) {
        
        // 保存之前的路径
        if (currentPath && currentPath.points.length > 1) {
          transformedPaths.push(currentPath);
        }
        
        // 创建新路径
        currentPath = {
          color: color,
          points: []
        };
        
        // 添加起点，保留原始A4坐标
        // 注意：API返回的路径数据是A4坐标系的，我们只需要存储原始A4坐标
        // 不需要减去页面左边距，因为在redrawAnnotations中会正确处理
        currentPath.points.push({
          x: segment.x1,
          y: segment.y1,
          width: width
        });
        
        // 确保立即将新路径添加到数组中
        transformedPaths.push(currentPath);
      }
      
      // 添加终点，保留原始A4坐标
      currentPath.points.push({
        x: segment.x2,
        y: segment.y2,
        width: width
      });
      
      // 更新最后一个点
      lastPoint = {
        x2: segment.x2,
        y2: segment.y2,
        color: color
      };
    });
    
    console.log(`转换后的路径数:${transformedPaths.length}`);
    
    return transformedPaths;
  },

  // 页面显示时执行
  onShow() {
    // 初始化 movable-area 的位置信息
    wx.createSelectorQuery().select('.movable-area').boundingClientRect(rect => {
      if (rect) {
        this.movableAreaTop = rect.top;
        this.movableAreaLeft = rect.left;
        console.log('初始化 movable-area 位置:', { top: rect.top, left: rect.left });
      }
    }).exec();
    
    // 检查是否是从登录页面返回，并且要进入签名模式
    const app = getApp();
    const openId = wx.getStorageSync('openId');
    
    // 检查登录状态和等待签名标记
    if (openId && app.globalData.pendingSignature) {
      console.log('[PDF查看器] 检测到用户已登录并等待签名');
      // 清除全局标记
      app.globalData.pendingSignature = false;
      
      // 延迟一下再进入签名模式，确保页面已完全渲染
      setTimeout(() => {
        this.enterSigningMode();
      }, 500);
    }
  },

  // 防止滑动穿透
  preventTouchMove() {
    return false;
  },
  
  // 阻止事件冒泡
  stopPropagation(e) {
    // 阻止点击事件冒泡
    return false;
  },
  
  // 关闭登录框
  closeLoginModal() {
    this.setData({
      showLoginModal: false
    });
    
    // 恢复导航栏的层级
    wx.setTabBarStyle({
      zIndex: 10
    })
  },
  
  // 处理选择头像
  onChooseAvatar(e) {
    const { avatarUrl } = e.detail;
    if (!avatarUrl) {
      console.error('chooseAvatar failed, no avatarUrl received.');
      wx.showToast({ title: '选择头像失败', icon: 'none' });
      return;
    }
    
    console.log('步骤1: 收到原始头像路径:', avatarUrl);

    wx.showLoading({ title: '头像处理中...', mask: true });

    // 步骤2: 调用 compressImage "清洗"路径，获取可靠的临时文件
    wx.compressImage({
      src: avatarUrl,
      quality: 80, // 压缩质量
      success: (res) => {
        const reliablePath = res.tempFilePath;
        console.log('步骤2: 路径清洗成功，获得新的可靠路径:', reliablePath);
        
        // 步骤3: 使用新的、可靠的路径进行上传
        wx.uploadFile({
          url: request.BASE_URL + '/uploadAvatar',
          filePath: reliablePath,
          name: 'file',
          formData: { openId: wx.getStorageSync('openId') || '' },
          success: (uploadRes) => {
            wx.hideLoading();
            try {
              const data = JSON.parse(uploadRes.data);
              if (data && data.code === 200 && data.data) {
                // 只保存相对路径，不带上IMG_URL
                const imagePath = data.data;
                console.log('步骤4: 上传成功，保存相对路径:', imagePath);
                
                // 为了显示，仍然使用完整URL
                const fullImageUrl = IMG_URL + imagePath;
                console.log('用于显示的完整URL:', fullImageUrl);
                
                // 在tempUserInfo中保存相对路径
                this.setData({ 'tempUserInfo.avatarUrl': imagePath });
              } else {
                console.error('上传接口返回错误或数据格式不正确:', data);
                wx.showToast({ title: '上传失败[接口异常]', icon: 'none' });
              }
            } catch (err) {
              console.error('解析上传接口返回数据失败:', err);
              wx.showToast({ title: '上传失败[数据解析失败]', icon: 'none' });
            }
          },
          fail: (uploadErr) => {
            wx.hideLoading();
            console.error('步骤3: wx.uploadFile 接口调用失败:', uploadErr);
            wx.showToast({ title: '上传失败[网络错误]', icon: 'none' });
          }
        });
      },
      fail: (compressErr) => {
        wx.hideLoading();
        console.error('步骤2: wx.compressImage 路径清洗失败:', compressErr);
        wx.showToast({ title: '处理头像失败', icon: 'none' });
      }
    });
  },
  
  // 处理输入昵称
  onInputNickname(e) {
    const nickName = e.detail.value
    this.setData({
      'tempUserInfo.nickName': nickName
    })
  },
  
  // 处理登录
  handleLogin() {
    if (!this.data.tempUserInfo.nickName.trim()) {
      wx.showToast({
        title: '请输入昵称',
        icon: 'none'
      })
      return
    }
    
    // 显示加载中
    wx.showLoading({
      title: '登录中...',
      mask: true
    })
    
    // 生成随机UID
    const uid = this.data.tempUserInfo.uid || this.generateUID()
    
    // 判断头像是否是默认头像，如果是则不传
    const avatarUrl = this.data.tempUserInfo.avatarUrl === defaultAvatarUrl ? '' : this.data.tempUserInfo.avatarUrl;
    
    const userInfo = {
      avatarUrl: avatarUrl, // 不使用默认值，只保存相对路径
      nickName: this.data.tempUserInfo.nickName,
      uid: uid
    }
    
    // 获取用于显示的头像URL
    const displayAvatarUrl = userInfo.avatarUrl ? (IMG_URL + userInfo.avatarUrl) : defaultAvatarUrl;
          
    // 先更新本地UI状态，优化用户体验
          this.setData({
            showLoginModal: false
    })
    
    // 调用服务端登录接口
    this.doLoginWithServer(userInfo);
  },

  // 调用服务端登录接口
  doLoginWithServer(userInfo) {
    // 获取微信登录凭证
    wx.login({
      success: res => {
        if (res.code) {
          // 发送登录请求，直接传递code、avatarUrl和nickName参数
          api.user.wxLogin({
            code: res.code,
            avatarUrl: userInfo.avatarUrl, // 不添加默认值，如果为空则传空
            nickName: userInfo.nickName || ''
        })
          .then(result => {
            console.log('[登录流程] 登录接口调用成功，服务器返回:', result);
            
            // 服务端返回的数据已经是data字段的内容
            const serverData = result;
            console.log('[登录流程] 处理后的数据:', serverData);
            
            // 使用服务端返回的数据
            const serverAvatarUrl = serverData.avatarUrl || '';
            console.log('[登录流程] 服务端返回的头像URL:', serverAvatarUrl);
            
            const formattedJoinDate = serverData.createTime.split(' ')[0].replace(/-/g, '.');

            const updatedUserInfo = {
              nickName: serverData.nickName || userInfo.nickName,
              avatarUrl: serverAvatarUrl, // 使用服务端返回的头像URL
              uid: serverData.id,
              openId: serverData.openId,
              joinDate: formattedJoinDate
            };
            
            // 获取用于显示的头像URL
            const displayAvatarUrl = serverAvatarUrl ? (IMG_URL + serverAvatarUrl) : defaultAvatarUrl;
            console.log('[登录流程] 头像显示URL:', displayAvatarUrl);
            
            // 存储凭证(openId)的操作已在request.js中自动完成
            console.log('[登录流程] 准备更新本地缓存中的userInfo');
            
            // 更新用户信息
            wx.setStorageSync('userInfo', {
              ...updatedUserInfo,
              displayAvatarUrl: displayAvatarUrl // 本地存储时添加显示用的完整URL
            });
            console.log('[登录流程] userInfo更新完毕');
            
            // 更新全局登录状态
            const app = getApp()
            app.globalData.isLoggedIn = true
            app.globalData.userInfo = {
              ...updatedUserInfo,
              displayAvatarUrl: displayAvatarUrl // 全局数据使用完整URL
            }

            wx.showToast({
              title: '登录成功',
              icon: 'success'
            })
        
        // 延迟一下再进入签名模式
        setTimeout(() => {
          this.enterSigningMode();
        }, 500);
      })
      .catch(err => {
            console.error('登录失败', err)
            // 错误提示已在request.js中统一处理
            
            // 更新全局登录状态
            const app = getApp()
            app.globalData.isLoggedIn = false
          })
          .finally(() => {
            wx.hideLoading()
          })
        } else {
          console.error('获取微信登录凭证失败', res)
        wx.showToast({
          title: '登录失败，请重试',
          icon: 'none'
          })
          wx.hideLoading()
    }
  },
      fail: err => {
        console.error('wx.login调用失败', err)
        wx.showToast({
          title: '登录失败，请重试',
          icon: 'none'
        })
        wx.hideLoading()
      }
    })
  },
  
  // 生成随机UID
  generateUID() {
    return Math.floor(10000000 + Math.random() * 90000000).toString()
  },

  // 导出签名数据
  exportSignature(e) {
    // 安全地阻止事件冒泡
    if (e && typeof e.stopPropagation === 'function') {
      e.stopPropagation();
    }
    
    // 安全地获取签名openId
    if (!e || !e.currentTarget || !e.currentTarget.dataset) {
      wx.showToast({
        title: '获取签名信息失败',
        icon: 'none'
      });
      return;
    }
    
    const signatureOpenId = e.currentTarget.dataset.openid;
    const signModel = this.data.signModel;
    const fileId = this.data.fileId;
    
    if (!fileId) {
      wx.showToast({
        title: '缺少文件ID，无法导出',
        icon: 'none'
      });
      return;
    }
    
    // 构建导出参数
    let exportParams = {
      signModel: signModel
    };
    
    if (signModel === 1) {
      // 单签模式：传递当前行的openId + fileId + signModel
      console.log('[调试-导出] 点击的签名openId:', signatureOpenId);
      console.log('[调试-导出] 当前签名列表:', this.data.signatureList);
      
      const signatureItem = this.data.signatureList.find(item => item.openId === signatureOpenId);
      console.log('[调试-导出] 找到的签名项:', signatureItem);
      
      if (!signatureItem || !signatureItem.openId) {
        console.log('[调试-导出] 签名项或openId不存在 - signatureItem:', signatureItem);
        wx.showToast({
          title: '缺少签名用户信息，无法导出',
          icon: 'none'
        });
        return;
      }
      
      exportParams = {
        openId: signatureItem.openId,
        fileId: fileId,
        signModel: signModel
      };
      
      console.log('[调试-导出] 单签模式参数:', exportParams);
      console.log('[调试-导出] 使用的openId:', signatureItem.openId, '对应用户:', signatureItem.nickName);
    } else if (signModel === 2) {
      // 多签模式：使用页面初始化时获取的openId
      const articleOpenId = this.data.articleOpenId;
      const currentUserOpenId = wx.getStorageSync('openId');
      
      if (!currentUserOpenId) {
        wx.showToast({
          title: '请先登录',
          icon: 'none'
        });
        return;
      }
      
      // 优先使用页面初始化时获取的openId，如果没有则使用当前用户的openId
      const targetOpenId = articleOpenId || currentUserOpenId;
      
      exportParams = {
        fileId: fileId,
        openId: targetOpenId,
        signModel: signModel
      };
      
      console.log('[导出] 多签模式参数（使用已保存的openId）:', exportParams, '来源:', articleOpenId ? 'getArticleImg' : 'localStorage');
    } else {
      wx.showToast({
        title: '未知的签名模式',
        icon: 'none'
      });
      return;
    }
    
    wx.showLoading({
      title: '导出中...',
      mask: true
    });
    
    // 调用导出API
    api.article.export(exportParams)
      .then(res => {
        wx.hideLoading();
        console.log('[导出] 导出成功:', res);
        
        // 构造文档URL
        const documentUrl = this.data.IMG_URL + res;
        console.log('[导出] 准备打开文档:', documentUrl);
        
        // 保存页面实例引用
        const self = this;
        
        // 下载并直接分享文档
        wx.downloadFile({
          url: documentUrl,
          success: function(downloadRes) {
            console.log('[导出] 文档下载成功:', downloadRes.tempFilePath);
            
            // 询问用户是否要分享文件
            wx.showModal({
              title: '文档导出成功',
              content: '是否要将此文档分享给好友？',
              confirmText: '分享',
              cancelText: '查看文档',
              success: function(modalRes) {
                if (modalRes.confirm) {
                  // 用户选择分享
                  const fileName = self.data.documentTitle ? 
                    `${self.data.documentTitle}` : 
                    '签名文档.docx';
                  wx.shareFileMessage({
                    filePath: downloadRes.tempFilePath,
                    fileName: fileName,
                    success: function() {
                      console.log('[导出] 文档分享成功');
                      wx.showToast({
                        title: '分享成功',
                        icon: 'success'
                      });
                    },
                    fail: function(shareErr) {
                      console.error('[导出] 文档分享失败:', shareErr);
                      wx.showToast({
                        title: '分享失败',
                        icon: 'none'
                      });
                    }
                  });
                } else {
                  // 用户选择查看文档
                  wx.openDocument({
                    filePath: downloadRes.tempFilePath,
                    fileType: 'docx',
                    success: function() {
                      console.log('[导出] 文档打开成功');
                      wx.showToast({
                        title: '文档已打开',
                        icon: 'success'
                      });
                    },
                    fail: function(err) {
                      console.error('[导出] 文档打开失败:', err);
                      wx.showToast({
                        title: '文档打开失败',
                        icon: 'none'
                      });
                    }
                  });
                }
              }
            });
          },
          fail: function(err) {
            console.error('[导出] 文档下载失败:', err);
            wx.showToast({
              title: '文档下载失败',
              icon: 'none'
            });
          }
        });
      })
      .catch(err => {
        wx.hideLoading();
        console.error('[导出] 导出失败:', err);
        wx.showToast({
          title: '导出失败',
          icon: 'none'
        });
      });
  },
  
  // 导出所有签名数据
  exportAllSignatures() {
    const signModel = this.data.signModel;
    const fileId = this.data.fileId;
    
    if (!fileId) {
      wx.showToast({
        title: '缺少文件ID，无法导出',
        icon: 'none'
      });
      return;
    }
    
    // 构建导出参数
    let exportParams = {
      signModel: signModel
    };
    
    if (signModel === 1) {
      // 单签模式：需要导出所有签名用户的数据
      // 对于单签模式的"导出所有"，我们可以传递所有签名用户的openId列表
      // 或者让后端根据fileId和signModel来处理所有相关数据
      const allOpenIds = this.data.signatureList
        .filter(item => item.openId)
        .map(item => item.openId);
      
      if (allOpenIds.length === 0) {
        wx.showToast({
          title: '没有签名数据可导出',
          icon: 'none'
        });
        return;
      }
      
      exportParams = {
        fileId: fileId,
        signModel: signModel,
        openIds: allOpenIds // 传递所有签名用户的openId列表
      };
      
      console.log('[导出所有] 单签模式参数:', exportParams);
    } else if (signModel === 2) {
      // 多签模式：使用页面初始化时获取的openId
      const articleOpenId = this.data.articleOpenId;
      const currentUserOpenId = wx.getStorageSync('openId');
      
      if (!currentUserOpenId) {
        wx.showToast({
          title: '请先登录',
          icon: 'none'
        });
        return;
      }
      
      // 优先使用页面初始化时获取的openId，如果没有则使用当前用户的openId
      const targetOpenId = articleOpenId || currentUserOpenId;
      
      exportParams = {
        fileId: fileId,
        openId: targetOpenId,
        signModel: signModel
      };
      
      console.log('[导出所有] 多签模式参数（使用已保存的openId）:', exportParams, '来源:', articleOpenId ? 'getArticleImg' : 'localStorage');
    } else {
      wx.showToast({
        title: '未知的签名模式',
        icon: 'none'
      });
      return;
    }
    
    wx.showLoading({
      title: '导出中...',
      mask: true
    });
    
    // 调用导出API
    api.article.export(exportParams)
      .then(res => {
        wx.hideLoading();
        console.log('[导出所有] 导出成功:', res);
        
        // 构造文档URL
        const documentUrl = this.data.IMG_URL + res;
        console.log('[导出所有] 准备打开文档:', documentUrl);
        
        // 保存页面实例引用
        const self = this;
        
        // 下载并直接分享文档
        wx.downloadFile({
          url: documentUrl,
          success: function(downloadRes) {
            console.log('[导出所有] 文档下载成功:', downloadRes.tempFilePath);
            
            // 询问用户是否要分享文件
            wx.showModal({
              title: '文档导出成功',
              content: '是否要将此文档分享给好友？',
              confirmText: '分享',
              cancelText: '查看文档',
              success: function(modalRes) {
                if (modalRes.confirm) {
                  // 用户选择分享
                  const fileName = self.data.documentTitle ? 
                    `${self.data.documentTitle}.docx` : 
                    '签名文档.docx';
                  wx.shareFileMessage({
                    filePath: downloadRes.tempFilePath,
                    fileName: fileName,
                    success: function() {
                      console.log('[导出所有] 文档分享成功');
                      wx.showToast({
                        title: '分享成功',
                        icon: 'success'
                      });
                    },
                    fail: function(shareErr) {
                      console.error('[导出所有] 文档分享失败:', shareErr);
                      wx.showToast({
                        title: '分享失败',
                        icon: 'none'
                      });
                    }
                  });
                } else {
                  // 用户选择查看文档
                  wx.openDocument({
                    filePath: downloadRes.tempFilePath,
                    fileType: 'docx',
                    success: function() {
                      console.log('[导出所有] 文档打开成功');
                      wx.showToast({
                        title: '文档已打开',
                        icon: 'success'
                      });
                    },
                    fail: function(err) {
                      console.error('[导出所有] 文档打开失败:', err);
                      wx.showToast({
                        title: '文档打开失败',
                        icon: 'none'
                      });
                    }
                  });
                }
              }
            });
          },
          fail: function(err) {
            console.error('[导出所有] 文档下载失败:', err);
            wx.showToast({
              title: '文档下载失败',
              icon: 'none'
            });
          }
        });
      })
      .catch(err => {
        wx.hideLoading();
        console.error('[导出所有] 导出失败:', err);
        wx.showToast({
          title: '导出失败',
          icon: 'none'
        });
      });
  },

  // 添加触摸开始事件处理函数
  onTouchStart(e) {
    // 检测是否是双指触摸，用于设置缩放中心点
    if (e.touches.length === 2) {
      // 计算两个触摸点的中心位置
      const touch1 = e.touches[0];
      const touch2 = e.touches[1];
      const centerX = (touch1.clientX + touch2.clientX) / 2;
      const centerY = (touch1.clientY + touch2.clientY) / 2;
      
      // 记录缩放中心点，可用于调试
      this.scaleCenter = { x: centerX, y: centerY };
      console.log('缩放中心点:', this.scaleCenter);
    }
  },
});